// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package ssa

import (
	"cmd/compile/internal/abi"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/src"
	"internal/buildcfg"
)

// 配置文件包含只读编译信息。
// 在编译早期创建一次，
// 并在所有编译中共享。
type Config struct {
	arch           string // “amd64”等。
	PtrSize        int64  // 4或8；cmd/internal/sys的副本。拱p更改
	RegSize        int64  // 4或8；cmd/internal/sys的副本。拱RegSize 
	Types          Types
	lowerBlock     blockRewriter  // 降低功能
	lowerValue     valueRewriter  // 降低功能
	splitLoad      valueRewriter  // 用于拆分合并负载操作的功能；仅用于某些体系结构
	registers      []Register     // 机器寄存器
	gpRegMask      regMask        // 通用整数寄存器掩码
	fpRegMask      regMask        // 浮点寄存器掩码
	fp32RegMask    regMask        // 浮点寄存器掩码
	fp64RegMask    regMask        // 浮点寄存器掩码
	specialRegMask regMask        // 特殊寄存器掩码
	intParamRegs   []int8         // 整数参数（输入/输出）寄存器的寄存器号
	floatParamRegs []int8         // 浮点参数（in/out）寄存器的寄存器号
	ABI1           *abi.ABIConfig // “ABIInternal”正在开发
	ABI0           *abi.ABIConfig
	GCRegMap       []*Register // 垃圾收集器寄存器映射，由GC寄存器索引
	FPReg          int8        // 帧指针的寄存器号，-1如果未使用
	LinkReg        int8        // 链接寄存器的寄存器号如果是通用寄存器，-1如果没有使用
	hasGReg        bool        // 拥有硬件g寄存器
	ctxt           *obj.Link   // 通用arch信息
	optimize       bool        // 进行优化
	noDuffDevice   bool        // 不要使用达夫的设备
	useSSE         bool        // 将SSE用于非浮点操作
	useAvg         bool        // 使用需要Avg*操作
	useHmul        bool        // 使用需要Hmul*操作
	SoftFloat      bool        // /
	Race           bool        // 种族检测器启用
	BigEndian      bool        // 
	UseFMA         bool        // 使用硬件FMA操作
}

type (
	blockRewriter func(*Block) bool
	valueRewriter func(*Value) bool
)

type Types struct {
	Bool       *types.Type
	Int8       *types.Type
	Int16      *types.Type
	Int32      *types.Type
	Int64      *types.Type
	UInt8      *types.Type
	UInt16     *types.Type
	UInt32     *types.Type
	UInt64     *types.Type
	Int        *types.Type
	Float32    *types.Type
	Float64    *types.Type
	UInt       *types.Type
	Uintptr    *types.Type
	String     *types.Type
	BytePtr    *types.Type // TODO:使用不安全。而是指针？
	Int32Ptr   *types.Type
	UInt32Ptr  *types.Type
	IntPtr     *types.Type
	UintptrPtr *types.Type
	Float32Ptr *types.Type
	Float64Ptr *types.Type
	BytePtrPtr *types.Type
}

// NewTypes创建并填充类型。
func NewTypes() *Types {
	t := new(Types)
	t.SetTypPtrs()
	return t
}

// settyptrs填充t。
func (t *Types) SetTypPtrs() {
	t.Bool = types.Types[types.TBOOL]
	t.Int8 = types.Types[types.TINT8]
	t.Int16 = types.Types[types.TINT16]
	t.Int32 = types.Types[types.TINT32]
	t.Int64 = types.Types[types.TINT64]
	t.UInt8 = types.Types[types.TUINT8]
	t.UInt16 = types.Types[types.TUINT16]
	t.UInt32 = types.Types[types.TUINT32]
	t.UInt64 = types.Types[types.TUINT64]
	t.Int = types.Types[types.TINT]
	t.Float32 = types.Types[types.TFLOAT32]
	t.Float64 = types.Types[types.TFLOAT64]
	t.UInt = types.Types[types.TUINT]
	t.Uintptr = types.Types[types.TUINTPTR]
	t.String = types.Types[types.TSTRING]
	t.BytePtr = types.NewPtr(types.Types[types.TUINT8])
	t.Int32Ptr = types.NewPtr(types.Types[types.TINT32])
	t.UInt32Ptr = types.NewPtr(types.Types[types.TUINT32])
	t.IntPtr = types.NewPtr(types.Types[types.TINT])
	t.UintptrPtr = types.NewPtr(types.Types[types.TUINTPTR])
	t.Float32Ptr = types.NewPtr(types.Types[types.TFLOAT32])
	t.Float64Ptr = types.NewPtr(types.Types[types.TFLOAT64])
	t.BytePtrPtr = types.NewPtr(types.NewPtr(types.Types[types.TUINT8]))
}

type Logger interface {
	// Logf记录来自编译器的消息。
	Logf(string, ...interface{})

	// 日志报告日志记录是否为不可操作
	// 一些日志记录调用占用的堆分配超过几个。
	Log() bool

	// 致命报告编译器错误并退出。
	Fatalf(pos src.XPos, msg string, args ...interface{})

	// Warnl以“errorcheck”测试所需的形式编写编译器消息
	Warnl(pos src.XPos, fmt_ string, args ...interface{})

	// 转发来自gc的调试标志
	Debug_checknil() bool
}

type Frontend interface {
	CanSSA(t *types.Type) bool

	Logger

	// StringData返回指向给定字符串内容的符号。
	StringData(string) *obj.LSym

	// Auto返回给定类型的自动变量的节点。
	// SSA编译器使用此函数为溢出分配空间。
	Auto(src.XPos, *types.Type) *ir.Name

	// 给定复合类型的名称，返回我们应该使用的名称
	// 用于该复合类型的部分。
	SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot

	// Line返回一个描述给定位置的字符串。
	Line(src.XPos) string

	// AllocFrame为所有活动自动变量指定帧偏移量。
	AllocFrame(f *Func)

	// Syslook返回运行时函数/变量的符号，其名称为
	// 。
	Syslook(string) *obj.LSym

	// UseWriteBarrier报告是否启用了写屏障
	UseWriteBarrier() bool

	// SetWBPos表示已在pos位置将写屏障插入此函数中。
	// MyImportPath为正在编译的函数提供导入名称（大致为包）。
	SetWBPos(pos src.XPos)

	MyImportPath() string
}

// NewConfig返回给定体系结构的新配置对象。
func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat bool) *Config {
	c := &Config{arch: arch, Types: types}
	c.useAvg = true
	c.useHmul = true
	switch arch {
	case "amd64":
		c.PtrSize = 8
		c.RegSize = 8
		c.lowerBlock = rewriteBlockAMD64
		c.lowerValue = rewriteValueAMD64
		c.splitLoad = rewriteValueAMD64splitload
		c.registers = registersAMD64[:]
		c.gpRegMask = gpRegMaskAMD64
		c.fpRegMask = fpRegMaskAMD64
		c.specialRegMask = specialRegMaskAMD64
		c.intParamRegs = paramIntRegAMD64
		c.floatParamRegs = paramFloatRegAMD64
		c.FPReg = framepointerRegAMD64
		c.LinkReg = linkRegAMD64
		c.hasGReg = true
	case "386":
		c.PtrSize = 4
		c.RegSize = 4
		c.lowerBlock = rewriteBlock386
		c.lowerValue = rewriteValue386
		c.splitLoad = rewriteValue386splitload
		c.registers = registers386[:]
		c.gpRegMask = gpRegMask386
		c.fpRegMask = fpRegMask386
		c.FPReg = framepointerReg386
		c.LinkReg = linkReg386
		c.hasGReg = false
	case "arm":
		c.PtrSize = 4
		c.RegSize = 4
		c.lowerBlock = rewriteBlockARM
		c.lowerValue = rewriteValueARM
		c.registers = registersARM[:]
		c.gpRegMask = gpRegMaskARM
		c.fpRegMask = fpRegMaskARM
		c.FPReg = framepointerRegARM
		c.LinkReg = linkRegARM
		c.hasGReg = true
	case "arm64":
		c.PtrSize = 8
		c.RegSize = 8
		c.lowerBlock = rewriteBlockARM64
		c.lowerValue = rewriteValueARM64
		c.registers = registersARM64[:]
		c.gpRegMask = gpRegMaskARM64
		c.fpRegMask = fpRegMaskARM64
		c.intParamRegs = paramIntRegARM64
		c.floatParamRegs = paramFloatRegARM64
		c.FPReg = framepointerRegARM64
		c.LinkReg = linkRegARM64
		c.hasGReg = true
		c.noDuffDevice = buildcfg.GOOS == "darwin" || buildcfg.GOOS == "ios" // 达尔文链接器无法处理带有非零加数的BR26 reloc 
	case "ppc64":
		c.BigEndian = true
		fallthrough
	case "ppc64le":
		c.PtrSize = 8
		c.RegSize = 8
		c.lowerBlock = rewriteBlockPPC64
		c.lowerValue = rewriteValuePPC64
		c.registers = registersPPC64[:]
		c.gpRegMask = gpRegMaskPPC64
		c.fpRegMask = fpRegMaskPPC64
		c.intParamRegs = paramIntRegPPC64
		c.floatParamRegs = paramFloatRegPPC64
		c.FPReg = framepointerRegPPC64
		c.LinkReg = linkRegPPC64
		c.hasGReg = true
	case "mips64":
		c.BigEndian = true
		fallthrough
	case "mips64le":
		c.PtrSize = 8
		c.RegSize = 8
		c.lowerBlock = rewriteBlockMIPS64
		c.lowerValue = rewriteValueMIPS64
		c.registers = registersMIPS64[:]
		c.gpRegMask = gpRegMaskMIPS64
		c.fpRegMask = fpRegMaskMIPS64
		c.specialRegMask = specialRegMaskMIPS64
		c.FPReg = framepointerRegMIPS64
		c.LinkReg = linkRegMIPS64
		c.hasGReg = true
	case "s390x":
		c.PtrSize = 8
		c.RegSize = 8
		c.lowerBlock = rewriteBlockS390X
		c.lowerValue = rewriteValueS390X
		c.registers = registersS390X[:]
		c.gpRegMask = gpRegMaskS390X
		c.fpRegMask = fpRegMaskS390X
		c.FPReg = framepointerRegS390X
		c.LinkReg = linkRegS390X
		c.hasGReg = true
		c.noDuffDevice = true
		c.BigEndian = true
	case "mips":
		c.BigEndian = true
		fallthrough
	case "mipsle":
		c.PtrSize = 4
		c.RegSize = 4
		c.lowerBlock = rewriteBlockMIPS
		c.lowerValue = rewriteValueMIPS
		c.registers = registersMIPS[:]
		c.gpRegMask = gpRegMaskMIPS
		c.fpRegMask = fpRegMaskMIPS
		c.specialRegMask = specialRegMaskMIPS
		c.FPReg = framepointerRegMIPS
		c.LinkReg = linkRegMIPS
		c.hasGReg = true
		c.noDuffDevice = true
	case "riscv64":
		c.PtrSize = 8
		c.RegSize = 8
		c.lowerBlock = rewriteBlockRISCV64
		c.lowerValue = rewriteValueRISCV64
		c.registers = registersRISCV64[:]
		c.gpRegMask = gpRegMaskRISCV64
		c.fpRegMask = fpRegMaskRISCV64
		c.FPReg = framepointerRegRISCV64
		c.hasGReg = true
	case "wasm":
		c.PtrSize = 8
		c.RegSize = 8
		c.lowerBlock = rewriteBlockWasm
		c.lowerValue = rewriteValueWasm
		c.registers = registersWasm[:]
		c.gpRegMask = gpRegMaskWasm
		c.fpRegMask = fpRegMaskWasm
		c.fp32RegMask = fp32RegMaskWasm
		c.fp64RegMask = fp64RegMaskWasm
		c.FPReg = framepointerRegWasm
		c.LinkReg = linkRegWasm
		c.hasGReg = true
		c.noDuffDevice = true
		c.useAvg = false
		c.useHmul = false
	default:
		ctxt.Diag("arch %s not implemented", arch)
	}
	c.ctxt = ctxt
	c.optimize = optimize
	c.useSSE = true
	c.UseFMA = true
	c.SoftFloat = softfloat
	if softfloat {
		c.floatParamRegs = nil // 在软浮点模式下没有FP寄存器
	}

	c.ABI0 = abi.NewABIConfig(0, 0, ctxt.FixedFrameSize())
	c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.FixedFrameSize())

	// 在计划9上，注释处理程序中不允许浮点操作。
	if buildcfg.GOOS == "plan9" {
		// 不要在计划9上使用FMA 
		c.UseFMA = false

		// 不要在计划9 AMD64上使用达夫设备和SSE。
		if arch == "amd64" {
			c.noDuffDevice = true
			c.useSSE = false
		}
	}

	if ctxt.Flag_shared {
		// LoweredWB是一个秘密呼叫，在
		// 共享模式下对386的呼叫被obj6重写。通过
		// GOT，它会重击BX。
		opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 3 // BX 
	}

	// 创建GC寄存器映射索引。
	// TODO:这只用于调试打印。也许是导出配置。登记？
	gcRegMapSize := int16(0)
	for _, r := range c.registers {
		if r.gcNum+1 > gcRegMapSize {
			gcRegMapSize = r.gcNum + 1
		}
	}
	c.GCRegMap = make([]*Register, gcRegMapSize)
	for i, r := range c.registers {
		if r.gcNum != -1 {
			c.GCRegMap[r.gcNum] = &c.registers[i]
		}
	}

	return c
}

func (c *Config) Ctxt() *obj.Link { return c.ctxt }
